// 程序来源：https://github.com/musescore/MuseScore/blob/f1f46bdae02fd5b8fb037d8f5b16c60543daa26b/mscore/musescore.cpp#L5268
//=============================================================================
//  MuseScore
//  Music Composition & Notation
//
//  Copyright (C) 2002-2016 Werner Schweer
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License version 2
//  as published by the Free Software Foundation and appearing in
//  the file LICENCE.GPL
//=============================================================================

#include <fenv.h>

#include "palettebox.h"
#include "config.h"
#include "musescore.h"
#include "scoreview.h"
#include "libmscore/style.h"
#include "libmscore/score.h"
#include "instrdialog.h"
#include "preferences.h"
#include "prefsdialog.h"
#include "icons.h"
#include "textstyledialog.h"
#include "libmscore/xml.h"
#include "seq.h"
#include "libmscore/tempo.h"
#include "libmscore/sym.h"
#include "pagesettings.h"
#include "debugger/debugger.h"
#include "editstyle.h"
#include "playpanel.h"
#include "libmscore/page.h"
#include "mixer.h"
#include "selectionwindow.h"
#include "palette.h"
#include "palettebox.h"
#include "libmscore/part.h"
#include "libmscore/drumset.h"
#include "libmscore/instrtemplate.h"
#include "libmscore/note.h"
#include "libmscore/staff.h"
#include "driver.h"
#include "libmscore/harmony.h"
#include "magbox.h"
#include "libmscore/sig.h"
#include "libmscore/undo.h"
#include "synthcontrol.h"
#include "pianoroll.h"
#include "drumroll.h"
#include "scoretab.h"
#include "timedialog.h"
#include "keyedit.h"
#include "harmonyedit.h"
#include "navigator.h"
#include "importmidi/importmidi_panel.h"
#include "libmscore/chord.h"
#include "mstyle/mstyle.h"
#include "mstyle/mconfig.h"
#include "libmscore/segment.h"
#include "editraster.h"
#include "pianotools.h"
#include "mediadialog.h"
#include "workspace.h"
#include "selectdialog.h"
#include "selectnotedialog.h"
#include "transposedialog.h"
#include "metaedit.h"
#include "inspector/inspector.h"
#ifdef OMR
#include "omrpanel.h"
#endif
#include "shortcut.h"
#ifdef SCRIPT_INTERFACE
#include "pluginCreator.h"
#include "pluginManager.h"
#endif
#include "helpBrowser.h"
#include "drumtools.h"
#include "editstafftype.h"
#include "texttools.h"
#include "textpalette.h"
#include "resourceManager.h"
#include "scoreaccessibility.h"

#include "libmscore/mscore.h"
#include "libmscore/system.h"
#include "libmscore/measure.h"
#include "libmscore/chordlist.h"
#include "libmscore/volta.h"
#include "libmscore/lasso.h"
#include "libmscore/excerpt.h"

#include "driver.h"

#include "effects/zita1/zita.h"
#include "effects/compressor/compressor.h"
#include "effects/noeffect/noeffect.h"
#include "synthesizer/synthesizer.h"
#include "synthesizer/synthesizergui.h"
#include "synthesizer/msynthesizer.h"
#include "fluid/fluid.h"
#include "qmlplugin.h"
#include "accessibletoolbutton.h"
#include "toolbuttonmenu.h"
#include "searchComboBox.h"
#include "startcenter.h"
#include "help.h"
#include "awl/aslider.h"

#ifdef AEOLUS
extern Ms::Synthesizer *createAeolus();
#endif
#ifdef ZERBERUS
extern Ms::Synthesizer *createZerberus();
#endif

#ifdef QT_NO_DEBUG
Q_LOGGING_CATEGORY(undoRedo, "undoRedo", QtCriticalMsg)
#else
Q_LOGGING_CATEGORY(undoRedo, "undoRedo", QtCriticalMsg)
//      Q_LOGGING_CATEGORY(undoRedo, "undoRedo")
#endif

//---------------------------------------------------------
//   main
//---------------------------------------------------------

int main(int argc, char *av[])
{
#ifndef NDEBUG
    qSetMessagePattern("%{file}:%{function}: %{message}");
    checkProperties();
#endif

    QApplication::setDesktopSettingsAware(true);
#if defined(QT_DEBUG) && defined(Q_OS_WIN)
    qInstallMessageHandler(mscoreMessageHandler);
#endif

    QFile f(":/revision.h");
    f.open(QIODevice::ReadOnly);
    revision = QString(f.readAll()).trimmed();
    f.close();

    MuseScoreApplication *app;
    if (MuseScore::unstable())
    {
        app = new MuseScoreApplication("mscore-dev3", argc, av);
        QCoreApplication::setApplicationName("MuseScoreDevelopment");
    }
    else
    {
        app = new MuseScoreApplication("mscore3", argc, av);
        QCoreApplication::setApplicationName("MuseScore3");
    }
    QCoreApplication::setOrganizationName("MuseScore");
    QCoreApplication::setOrganizationDomain("musescore.org");
    QCoreApplication::setApplicationVersion(VERSION);
    QAccessible::installFactory(AccessibleScoreView::ScoreViewFactory);
    QAccessible::installFactory(AccessibleSearchBox::SearchBoxFactory);
    QAccessible::installFactory(Awl::AccessibleAbstractSlider::AbstractSliderFactory);

    Q_INIT_RESOURCE(zita);

#ifndef Q_OS_MAC
    QSettings::setDefaultFormat(QSettings::IniFormat);
#endif

    QCommandLineParser parser;

    parser.addHelpOption();    // -?, -h, --help
    parser.addVersionOption(); // -v, --version

    // parser.addOption(QCommandLineOption({"v", "version"}, "Print version")); // see above
    parser.addOption(QCommandLineOption("long-version", "Print detailed version information"));
    parser.addOption(QCommandLineOption({"d", "debug"}, "Debug mode"));
    parser.addOption(QCommandLineOption({"L", "layout-debug"}, "Layout debug"));
    parser.addOption(QCommandLineOption({"s", "no-synthesizer"}, "No internal synthesizer"));
    parser.addOption(QCommandLineOption({"m", "no-midi"}, "No midi"));
    parser.addOption(QCommandLineOption({"a", "use-audio"}, "Use audio driver: jack, alsa, pulse, or portaudio", "driver"));
    parser.addOption(QCommandLineOption({"n", "new-score"}, "Start with new score"));
    parser.addOption(QCommandLineOption({"I", "dump-midi-in"}, "Dump midi input"));
    parser.addOption(QCommandLineOption({"O", "dump-midi-out"}, "Dump midi output"));
    parser.addOption(QCommandLineOption({"o", "export-to"}, "Export to 'file'; format depends on file extension", "file"));
    parser.addOption(QCommandLineOption({"r", "image-resolution"}, "Set output resolution for image export", "dpi"));
    parser.addOption(QCommandLineOption({"T", "trim-image"}, "Trim exported image with specified margin (in pixels)", "margin"));
    parser.addOption(QCommandLineOption({"x", "gui-scaling"}, "Set scaling factor for GUI elements", "factor"));
    parser.addOption(QCommandLineOption({"D", "monitor-resolution"}, "Specify monitor resolution", "dpi"));
    parser.addOption(QCommandLineOption({"S", "style"}, "Load style file", "style"));
    parser.addOption(QCommandLineOption({"p", "plugin"}, "Execure named plugin", "name"));
    parser.addOption(QCommandLineOption("template-mode", "Save template mode, no page size"));
    parser.addOption(QCommandLineOption({"F", "factory-settings"}, "Use factory settings"));
    parser.addOption(QCommandLineOption({"R", "revert-settings"}, "Revert to default preferences"));
    parser.addOption(QCommandLineOption({"i", "load-icons"}, "Load icons from INSTALLPATH/icons"));
    parser.addOption(QCommandLineOption({"j", "job"}, "process a conversion job", "file"));
    parser.addOption(QCommandLineOption({"e", "experimental"}, "Enable experimental features"));
    parser.addOption(QCommandLineOption({"c", "config-folder"}, "Override config/settings folder", "dir"));
    parser.addOption(QCommandLineOption({"t", "test-mode"}, "Set testMode flag for all files"));
    parser.addOption(QCommandLineOption({"M", "midi-operations"}, "Specify MIDI import operations file", "file"));
    parser.addOption(QCommandLineOption({"w", "no-webview"}, "No web view in start center"));
    parser.addOption(QCommandLineOption({"P", "export-score-parts"}, "Used with -o <file>.pdf, export score + parts"));
    parser.addOption(QCommandLineOption({"f", "force"}, "Used with -o, ignore warnings reg. score being corrupted or from wrong version"));

    parser.addPositionalArgument("scorefiles", "The files to open", "[scorefile...]");

    parser.process(QCoreApplication::arguments());

    // if (parser.isSet("v")) parser.showVersion(); // a) needs Qt >= 5.4 , b) instead we use addVersionOption()
    if (parser.isSet("long-version"))
    {
        printVersion("MuseScore");
        return EXIT_SUCCESS;
    }
    MScore::debugMode = parser.isSet("d");
    MScore::noHorizontalStretch = MScore::noVerticalStretch = parser.isSet("L");
    noSeq = parser.isSet("s");
    noMidi = parser.isSet("m");
    if (parser.isSet("a"))
    {
        audioDriver = parser.value("a");
        if (audioDriver.isEmpty())
            parser.showHelp(EXIT_FAILURE);
    }
    startWithNewScore = parser.isSet("n");
    externalIcons = parser.isSet("i");
    midiInputTrace = parser.isSet("I");
    midiOutputTrace = parser.isSet("O");

    if ((converterMode = parser.isSet("o")))
    {
        MScore::noGui = true;
        outFileName = parser.value("o");
        if (outFileName.isEmpty())
            parser.showHelp(EXIT_FAILURE);
    }
    if ((processJob = parser.isSet("j")))
    {
        MScore::noGui = true;
        converterMode = true;
        jsonFileName = parser.value("j");
        if (jsonFileName.isEmpty())
        {
            fprintf(stderr, "json file name missing\n");
            parser.showHelp(EXIT_FAILURE);
        }
    }
    if ((pluginMode = parser.isSet("p")))
    {
        MScore::noGui = true;
        pluginName = parser.value("p");
        if (pluginName.isEmpty())
            parser.showHelp(EXIT_FAILURE);
    }
    MScore::saveTemplateMode = parser.isSet("template-mode");
    if (parser.isSet("r"))
    {
        QString temp = parser.value("r");
        if (temp.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        converterDpi = temp.toDouble();
    }
    if (parser.isSet("T"))
    {
        QString temp = parser.value("T");
        if (temp.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        bool ok = false;
        trimMargin = temp.toInt(&ok);
        if (!ok)
            trimMargin = -1;
    }
    if (parser.isSet("x"))
    {
        QString temp = parser.value("x");
        if (temp.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        bool ok = false;
        guiScaling = temp.toDouble(&ok);
        if (!ok)
            guiScaling = 0.0;
    }
    if (parser.isSet("D"))
    {
        QString temp = parser.value("D");
        if (temp.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        bool ok = 0.0;
        userDPI = temp.toDouble(&ok);
        if (!ok)
            userDPI = 0.0;
    }
    if (parser.isSet("S"))
    {
        styleFile = parser.value("S");
        if (styleFile.isEmpty())
            parser.showHelp(EXIT_FAILURE);
    }
    useFactorySettings = parser.isSet("F");
    deletePreferences = (useFactorySettings || parser.isSet("R"));
    enableExperimental = parser.isSet("e");
    if (parser.isSet("c"))
    {
        QString path = parser.value("c");
        if (path.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        QDir dir;
        if (dir.exists(path))
        {
            QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, path);
            QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, path);
            dataPath = path;
        }
    }
    enableTestMode = parser.isSet("t");
    if (parser.isSet("M"))
    {
        QString temp = parser.value("M");
        if (temp.isEmpty())
            parser.showHelp(EXIT_FAILURE);
        preferences.midiImportOperations.setOperationsFile(temp);
    }
    noWebView = parser.isSet("w");
    exportScoreParts = parser.isSet("export-score-parts");
    if (exportScoreParts && !converterMode)
        parser.showHelp(EXIT_FAILURE);
    ignoreWarnings = parser.isSet("f");

    QStringList argv = parser.positionalArguments();

    mscoreGlobalShare = getSharePath();
    iconPath = externalIcons ? mscoreGlobalShare + QString("icons/") : QString(":/data/icons/");

    if (!converterMode && !pluginMode)
    {
        if (!argv.isEmpty())
        {
            int ok = true;
            for (const QString &message : argv)
            {
                QFileInfo fi(message);
                if (!app->sendMessage(fi.absoluteFilePath()))
                {
                    ok = false;
                    break;
                }
            }
            if (ok)
                return 0;
        }
        else if (app->sendMessage(QString("")))
            return 0;
    }

    if (dataPath.isEmpty())
        dataPath = QStandardPaths::writableLocation(QStandardPaths::DataLocation);

    if (deletePreferences)
    {
        QDir(dataPath).removeRecursively();
        QSettings settings;
        QFile::remove(settings.fileName() + ".lock"); // forcibly remove lock
        QFile::remove(settings.fileName());
        settings.clear();
    }

    // create local plugin directory
    // if not already there:
    QDir().mkpath(dataPath + "/plugins");

    if (MScore::debugMode)
        qDebug("global share: <%s>", qPrintable(mscoreGlobalShare));

    // set translator before preferences are read to get
    //    translations for all shortcuts
    //
    if (useFactorySettings)
        localeName = "system";
    else
    {
        QSettings s;
        localeName = s.value("language", "system").toString();
    }

    setMscoreLocale(localeName);

    Shortcut::init();
    preferences.init();

    QNetworkProxyFactory::setUseSystemConfiguration(true);

    MScore::init(); // initialize libmscore
    if (!MScore::testMode)
    {
        QSizeF psf = QPrinter().paperSize(QPrinter::Inch);
        PaperSize ps("system", psf.width(), psf.height());
        PageFormat pf;
        pf.setSize(&ps);
        pf.setPrintableWidth(psf.width() - 20.0 / INCH);
        MScore::defaultStyle()->setPageFormat(pf);
    }

#ifdef SCRIPT_INTERFACE
    qmlRegisterType<QmlPlugin>("MuseScore", 1, 0, "MuseScore");
#endif
    if (MScore::debugMode)
    {
        qDebug("DPI %f", DPI);

        QScreen *screen = QGuiApplication::primaryScreen();
        qDebug() << "Information for screen:" << screen->name();
        qDebug() << "  Available geometry:" << screen->availableGeometry().x() << screen->availableGeometry().y() << screen->availableGeometry().width() << "x" << screen->availableGeometry().height();
        qDebug() << "  Available size:" << screen->availableSize().width() << "x" << screen->availableSize().height();
        qDebug() << "  Available virtual geometry:" << screen->availableVirtualGeometry().x() << screen->availableVirtualGeometry().y() << screen->availableVirtualGeometry().width() << "x" << screen->availableVirtualGeometry().height();
        qDebug() << "  Available virtual size:" << screen->availableVirtualSize().width() << "x" << screen->availableVirtualSize().height();
        qDebug() << "  Depth:" << screen->depth() << "bits";
        qDebug() << "  Geometry:" << screen->geometry().x() << screen->geometry().y() << screen->geometry().width() << "x" << screen->geometry().height();
        qDebug() << "  Logical DPI:" << screen->logicalDotsPerInch();
        qDebug() << "  Logical DPI X:" << screen->logicalDotsPerInchX();
        qDebug() << "  Logical DPI Y:" << screen->logicalDotsPerInchY();
        qDebug() << "  Physical DPI:" << screen->physicalDotsPerInch();
        qDebug() << "  Physical DPI X:" << screen->physicalDotsPerInchX();
        qDebug() << "  Physical DPI Y:" << screen->physicalDotsPerInchY();
        qDebug() << "  Physical size:" << screen->physicalSize().width() << "x" << screen->physicalSize().height() << "mm";
        qDebug() << "  Refresh rate:" << screen->refreshRate() << "Hz";
        qDebug() << "  Size:" << screen->size().width() << "x" << screen->size().height();
        qDebug() << "  Virtual geometry:" << screen->virtualGeometry().x() << screen->virtualGeometry().y() << screen->virtualGeometry().width() << "x" << screen->virtualGeometry().height();
        qDebug() << "  Virtual size:" << screen->virtualSize().width() << "x" << screen->virtualSize().height();
    }

    if (!useFactorySettings)
        preferences.read();

    preferences.readDefaultStyle();

    if (converterDpi == 0)
        converterDpi = preferences.pngResolution;

    QSplashScreen *sc = 0;
    QTimer *stimer = 0;
    if (!MScore::noGui && preferences.showSplashScreen)
    {
        QPixmap pm(":/data/splash.png");
        sc = new QSplashScreen(pm);
        sc->setWindowTitle(QString("MuseScore Startup"));
#ifdef Q_OS_MAC // to have session dialog on top of splashscreen on mac
        sc->setWindowFlags(Qt::FramelessWindowHint);
#endif
        // show splash screen for 5 sec
        stimer = new QTimer(0);
        qApp->connect(stimer, SIGNAL(timeout()), sc, SLOT(close()));
        stimer->start(5000);
        sc->show();
        qApp->processEvents();
    }

    if (!converterMode && !pluginMode)
    {
        struct PaletteItem
        {
            QPalette::ColorRole role;
            const char *name;
            const char *color;
        };
        MgStyleConfigData::animationsEnabled = preferences.animations;
        MgStyle *st = new MgStyle;
        QApplication::setStyle(st);
        QPalette p(QApplication::palette());
        QSettings s;

        switch (preferences.globalStyle)
        {
        case MuseScoreStyleType::DARK:
        {
            static const PaletteItem pi[] = {
                {QPalette::Window, "WindowColor", "#525252"},
                {QPalette::WindowText, "WindowTextColor", "#FFFFFF"},
                {QPalette::Base, "BaseColor", "#424242"},
                {QPalette::AlternateBase, "AlternateBaseColor", "#626262"},
                {QPalette::Text, "TextColor", "#FFFFFF"},
                {QPalette::Button, "ButtonColor", "#525252"},
                {QPalette::ButtonText, "ButtonTextColor", "#FFFFFF"},
                {QPalette::BrightText, "BrightTextColor", "#000000"},

                //                            { QPalette::Light,           "LightColor",           "#00FF00" },
                //                            { QPalette::Midlight,        "MidlightTextColor",    "#00FF00" },
                //                            { QPalette::Dark,            "DarkTextColor",        "#00FF00" },
                //                            { QPalette::Mid,             "MidColor",             "#00FF00" },
                //                            { QPalette::Shadow,          "ShadowColor",          "#00FF00" },
                {QPalette::Highlight, "HighlightColor", "#88bff6"},
                //                            { QPalette::HighlightedText, "HighlightedTextColor", "#00FF00" },
                {QPalette::Link, "HighlightedTextColor", "#00ffff"},
                {QPalette::LinkVisited, "HighlightedTextColor", "#00ffff"},
                {QPalette::ToolTipBase, "ToolTipBaseColor", "#808080"},
                {QPalette::ToolTipText, "ToolTipTextColor", "#000000"},
            };
            for (auto i : pi)
                p.setColor(i.role, s.value(i.name, i.color).value<QColor>());
            break;
        }
        case MuseScoreStyleType::LIGHT:
            static const PaletteItem pi[] = {
                {QPalette::Window, "WindowColor", "#e3e3e3"},
                {QPalette::WindowText, "WindowTextColor", "#333333"},
                {QPalette::Base, "BaseColor", "#f9f9f9"},
                {QPalette::AlternateBase, "AlternateBaseColor", "#eeeeee"},
                {QPalette::Text, "TextColor", "#333333"},
                {QPalette::Button, "ButtonColor", "#c9c9c9"},
                {QPalette::ButtonText, "ButtonTextColor", "#333333"},
                {QPalette::BrightText, "BrightTextColor", "#000000"},
                {QPalette::ToolTipBase, "ToolTipBaseColor", "#fefac2"},
                {QPalette::ToolTipText, "ToolTipTextColor", "#000000"},
                {QPalette::Link, "LinkColor", "#3a80c6"},
                {QPalette::LinkVisited, "LinkVisitedColor", "#3a80c6"},
            };
            for (auto i : pi)
                p.setColor(i.role, s.value(i.name, i.color).value<QColor>());
            break;
        }
        QApplication::setPalette(p);

        qApp->setStyleSheet(
            "*:disabled {\n"
            "   color: gray\n"
            "}\n"
            "QGroupBox {\n"
            "font-weight: bold;\n"
            "}\n"
            "QGroupBox::title {\n"
            "   subcontrol-origin: margin; subcontrol-position: top left; padding: 5px 5px;\n"
            "}\n"
            "QDockWidget {\n"
            "   border: 1px solid lightgray;\n"
            "   titlebar-close-icon: url(:/data/icons/png/window-close.png);\n"
            "   titlebar-normal-icon: url(:/data/icons/png/window-float.png);\n"
            "   }\n"
            "QTabBar::close-button {\n"
            "   image: url(:/data/icons/png/window-close.png);\n"
            "   }\n"
            "QTabBar::close-button:hover {\n"
            "   image: url(:/data/icons/png/window-close-hover.png);\n"
            "   }");
        qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
    }
    else
        noSeq = true;

    genIcons();

    // Do not create sequencer and audio drivers if run with '-s'
    if (!noSeq)
    {
        seq = new Seq();
        MScore::seq = seq;
        Driver *driver = driverFactory(seq, audioDriver);
        synti = synthesizerFactory();
        if (driver)
        {
            MScore::sampleRate = driver->sampleRate();
            synti->setSampleRate(MScore::sampleRate);
            synti->init();

            seq->setDriver(driver);
        }
        else
        {
            // Do not delete the sequencer If we can't load driver.
            // Allow user to select the working driver later.
            MScore::sampleRate = 44100; // Would be changed when user changes driver
            synti->setSampleRate(MScore::sampleRate);
            synti->init();
        }
        seq->setMasterSynthesizer(synti);
    }
    else
    {
        seq = 0;
        MScore::seq = 0;
    }

    //
    // avoid font problems by overriding the environment
    //    fall back to "C" locale
    //

    // #ifndef Q_OS_WIN
    // setenv("LANG", "C", 1);
    // #endif
    // QLocale::setDefault(QLocale(QLocale::C));

    if (MScore::debugMode)
    {
        QStringList sl(QCoreApplication::libraryPaths());
        foreach (const QString &s, sl)
            qDebug("LibraryPath: <%s>", qPrintable(s));
    }

    // rastral size of font is 20pt = 20/72 inch = 20*DPI/72 dots
    //   staff has 5 lines = 4 * _spatium
    //   _spatium    = SPATIUM20;     // 20.0 / 72.0 * DPI / 4.0;

    if (!MScore::noGui)
    {
#ifndef Q_OS_MAC
        qApp->setWindowIcon(*icons[int(Icons::window_ICON)]);
#endif
        Workspace::initWorkspace();
    }

    mscore = new MuseScore();

    // create a score for internal use
    gscore = new MasterScore(MScore::baseStyle());
    gscore->style()->set(StyleIdx::MusicalTextFont, QString("Bravura Text"));
    ScoreFont *scoreFont = ScoreFont::fontFactory("Bravura");
    gscore->setScoreFont(scoreFont);
    gscore->setNoteHeadWidth(scoreFont->width(SymId::noteheadBlack, gscore->spatium()) / SPATIUM20);

    if (!noSeq)
    {
        if (!seq->init())
            qDebug("sequencer init failed");
    }

    // read languages list
    mscore->readLanguages(mscoreGlobalShare + "locale/languages.xml");

    QApplication::instance()->installEventFilter(mscore);

    mscore->setRevision(revision);

    int files = 0;
    bool restoredSession = false;
    if (MScore::noGui)
    {
#ifdef Q_OS_MAC
        // see issue #28706: Hangup in converter mode with MusicXML source
        qApp->processEvents();
#endif
        exit(processNonGui(argv) ? 0 : EXIT_FAILURE);
    }
    else
    {
        mscore->readSettings();
        QObject::connect(qApp, SIGNAL(messageReceived(const QString &)),
                         mscore, SLOT(handleMessage(const QString &)));

        static_cast<QtSingleApplication *>(qApp)->setActivationWindow(mscore, false);
        // count filenames specified on the command line
        // these are the non-empty strings remaining in argv
        foreach (const QString &name, argv)
        {
            if (!name.isEmpty())
                ++files;
        }
#ifdef Q_WS_MAC
        // app->paths contains files requested to be loaded by OS X
        // append these to argv and update file count
        foreach (const QString &name, app->paths)
        {
            if (!name.isEmpty())
            {
                argv << name;
                ++files;
            }
        }
#endif
        //
        // TODO: delete old session backups
        //
        restoredSession = mscore->restoreSession((preferences.sessionStart == SessionStart::LAST && (files == 0)));
        if (!restoredSession || files)
            loadScores(argv);
    }
    errorMessage = new QErrorMessage(mscore);
    mscore->loadPlugins();
    mscore->writeSessionFile(false);

#ifdef Q_OS_MAC
    // there's a bug in Qt showing the toolbar unified after switching showFullScreen(), showMaximized(),
    // showNormal()...
    mscore->setUnifiedTitleAndToolBarOnMac(false);
#endif

    mscore->changeState(mscore->noScore() ? STATE_DISABLED : STATE_NORMAL);
    mscore->show();

    if (mscore->hasToCheckForUpdate())
        mscore->checkForUpdate();

    if (!scoresOnCommandline && preferences.showStartcenter && (!restoredSession || mscore->scores().size() == 0))
    {
#ifdef Q_OS_MAC
        // ugly, but on mac we get an event when a file is open.
        // We can't get the event when the startcenter is shown.
        // So we let the event loop run a bit before showing the start center.
        QTimer *timer = new QTimer();
        timer->setSingleShot(true);
        QObject::connect(timer, &QTimer::timeout, [=]()
                         {
                  if (!scoresOnCommandline) {
                        getAction("startcenter")->setChecked(true);
                        mscore->showStartcenter(true);
                        }
                  timer->deleteLater(); });
        timer->start(500);
#else

        getAction("startcenter")->setChecked(true);
        mscore->showStartcenter(true);
#endif
    }

    mscore->showPlayPanel(preferences.showPlayPanel);
    QSettings settings;
    if (settings.value("synthControlVisible", false).toBool())
        mscore->showSynthControl(true);
    if (settings.value("mixerVisible", false).toBool())
        mscore->showMixer(true);

    return qApp->exec();
}
